home *** CD-ROM | disk | FTP | other *** search
- PAGE 60,132
- TITLE Xall - High speed eXeute in ALL subdirs utility
- SUBTTL General Program description
- ;-----------------------------------------------------------------------------;
- ; Xall - eXecute any command in current directory plus all subdirectories ;
- ;-----------------------------------------------------------------------------;
- ; XALL 1.0 ■ PCDATA TOOLKIT Copyright (c) 1990 Ziff Communications Co. ;
- ; PC Magazine ■ Wolfgang Stiller ;
- ; ;
- ;-----------------------------------------------------------------------------;
- ;Purpose: ;
- ; XALL will eXecute any command in the current directory plus all ;
- ; subdirectories below that one. This program is written for high ;
- ; speed execution (lean and mean!). ;
- ;-----------------------------------------------------------------------------;
- ;Syntax: ;
- ; ;
- ;XALL anyDOScommand ;
- ; ;
- ; "anyDOScommand" may be any batch file, program, or DOS command. Any ;
- ; programs or batch files should be located in a ;
- ; directory specified in the DOS path (PATH=). ;
- ;-----------------------------------------------------------------------------;
- ;Remarks: ;
- ; "anyDOScommand" will be executed first in the current directory and ;
- ; then in each subdirectory subordinate to the current directory. This ;
- ; program has been optimized for speed and efficiency of execution. If ;
- ; execution is terminated, you will be in the directory currently being ;
- ; processed. This program does NOT check for execution of other ;
- ; programs that change the drive or directory. (Speed is the goal!) ;
- ; XALL has advanced error recovery and provides clear explanations to ;
- ; PCDATA Toolkit user of what has gone wrong, such as an ;
- ; invalid COMSPEC environment variable. ;
- ; ;
- ; XALL will return the following DOS errorlevels: ;
- ; ;
- ; 00 - normal completion ;
- ; 32 - any abnormal occurance - indicates fatal termination. ;
- ;-----------------------------------------------------------------------------;
-
-
- ;-----------------------------------------------------------------;
- ; Constants: ;
- ;-----------------------------------------------------------------;
- BOX EQU 254 ;Small box character code
- CR EQU 0Dh ; Carriage return
- LF EQU 0Ah ; Line feed
- CRLF EQU 0A0D ; CR+LF in one word
- First_time EQU 00h ; Constant to indicate first time
- Not_First_Time EQU 0FFh ; indicate NOT first time
- Subdirectory_attrib EQU 10h ; Bit pattern to find directories
-
- CSEG SEGMENT
- ASSUME CS:CSEG, DS:CSEG,ES:CSEG,SS:CSEG
- ORG 2Ch ;Segment of environment found here
- Environment LABEL BYTE
-
- ORG 7DH ;Just before paramter area in PSP
- XALL_PARM LABEL BYTE
-
- ORG 80h ;Normal DOS PSP parameter area
- PSP_PARM LABEL BYTE
-
- ;*****************************************************************************
- ;** Main program begins here: XALL - Subdirectory Command eXecuter **
- ;** ---- **
- ;*****************************************************************************
-
- ORG 100h ;This is a .COM type program
- XALL:
- MOV SP,OFFSET STACK_TOP ;Create new stack
-
- MOV DX,OFFSET XALL_CR_MSG ;Copyright message
- MOV AH,09h ;DOS print string function
- INT 21h
-
- MOV BX,offset Program_top ;End of program + 15 (segment roundng)
- MOV CX,4 ;Prepare to div by 4 (calc # of paras)
- SHR BX,CL ;Convert to segment address
- MOV AH,4Ah ;Release uneeded memory
- INT 21h
-
- CALL Get_COMSPEC ;Locate the compsec in the environment
- CALL Create_EXEC_parm_BLOCK ;Create parameter block for DOS EXEC
- CALL Create_Command_tail ;Create /C command for COMMAND.COM
-
- ;***********************;
- ; MAIN loop begins here ;
- ;***********************;
- EXEC_Next_Command: ;Come here to execute a command
- ;in each directory
- CALL DISPLAY_XALL_MSG ;Display msg that we are this directry
-
- ;---------------------------------------------------------------------------;
- ; Use DOS EXEC function to invoke COMMAND.COM with user's specified command ;
- ; tail from the parameter area at 80h. ;
- LDS DX,[Command_Adr] ;DS:DX is address of command.com str
- MOV BX,OFFSET Parm_block ;ES:BX is adr of parameter block
- MOV AX,4b00h ;DOS EXEC sub-task function
- INT 21h ;COMMAND.COM now executing user's cmd
-
- ; Return from execution of DOS shell - all registers may be corrupted:
- MOV AX,CS ;CS is only OK register
- MOV ES,AX
- MOV DS,AX
- MOV SS,AX
- MOV SP,OFFSET Stack_top ;Reset stack pointer
- JC Handle_Exec_Error ;If DOS EXEC function failed handle it
-
- ;-----------------------------------------------------------------------------;
- ; Now find NEXT (or first) subdirectory below the current one ;
- ;-----------------------------------------------------------------------------;
- Find_another_SubDirectory:
- MOV DX,[DTA_Ptr] ;Tell DOS to use different DTA
- MOV AH,1Ah ;DOS set DTA function
- INT 21h
-
- CMP FF_Flag,First_time ;Is this first time in this directory?
- JNE Find_next ; IF not, do a find next
- MOV DX,OFFSET Global_str ; Else do an initial find on *.*
- MOV CX,Subdirectory_attrib ; find only subdirectories
- MOV AH,4Eh ; DOS FIND 1st function
- INT 21h
- JMP SHORT Validate_directory ;Skip the FIND NEXT function call
-
- Find_Next: ;Find the next directory
- MOV AH,4Fh ;DOS find next function
- INT 21h
-
- Validate_directory: ;Check that we found valid directory
- JC Return_to_Mother ;If find failed, Return to mother dir
- MOV DI,[DTA_Ptr] ;Get address of current DTA
-
- ; Check the file attribute bits in the DTA (is it a directory or a file?)
- TEST BYTE PTR [DI+21],Subdirectory_attrib ;Is this a directory?
- JE Find_Next ;If its not a directory keep looking
-
- ADD DI,30 ;Point to directory name in DTA
- CMP BYTE PTR [DI],'.' ;IS it a '.' or '..' dir entry?
- JE Find_Next ; IF so, ignore it and find next dir
-
- ADD [DTA_Ptr],43 ;Go down one level + use a new DTA
- MOV FF_Flag,First_time ;Set flag to do intial *.* dir find
-
- ; Change to new daughter directory:
- MOV DX,DI ;point to directory to change to
- MOV AH,3Bh ;DOS change directory function
- INT 21h
-
- JMP SHORT EXEC_Next_Command ;Go execute command in this new Dir
-
- ;-----------------------------------------------------------------------------;
- ; HANDLE EXEC ERROR - Produce specific error messages for the possible DOS ;
- ; return codes from the EXEC function which may reasonably;
- ; happen as a result of command or configuration error. ;
- ;-----------------------------------------------------------------------------;
- Handle_Exec_Error: ;Come here if, DOS EXEC func failed
- CMP AX,02 ;= file not found/path invalid ?
- JNE Handle_Exec_A ; If not, check other codes
- MOV DX, OFFSET EXEC_02_Msg ; Else put out appropriate error msg
- JMP Error_Exit ; Print error message and terminate
- Handle_Exec_A: ;Keep checking other possible codes:
- CMP AX,05 ;= Access denied return code?
- JNE Handle_Exec_B ; If not, check other codes
- MOV DX, OFFSET EXEC_05_Msg ; Else put out appropriate error msg
- JMP Error_Exit ; Print error message and terminate
- Handle_Exec_B: ;Keep checking other possible codes:
- CMP AX,08 ;= Isufficient memory return code?
- JNE Unexpected_error ; If not, its an unexpected error..
- MOV DX, OFFSET EXEC_08_Msg ; Else put out appropriate error msg
- JMP Error_Exit ; Print error message and terminate
- Unexpected_error: ;Put out a general catchall error msg
- MOV DX,OFFSET XALL_fail_msg ;message for unexpected errors
- JMP Error_Exit ; Print error message and terminate
-
- ;-----------------------------------------------------------------------------;
- ; R E T U R N T O M O T H E R - No more files in prior directory so we ;
- ; return to the previous level and find next;
- ;-----------------------------------------------------------------------------;
- Return_to_Mother: ;Go up one level to mother directory
- CMP [DTA_Ptr],OFFSET DTA_Area ;Are we back in original directory?
- JNZ Return_to_Prior_Dir ; If not, set directory back 1 level
- JMP Normal_termination ; If so, we are all done
-
- Return_to_Prior_Dir:
- MOV DX,OFFSET DotDot_str ;Point to ".." string (prev dir)
- MOV AH,3Bh ;DOS change dir function
- INT 21h ;Change to prior (mother) directory
-
- SUB [DTA_Ptr],43 ;Go back and re-use prior DTA
- MOV FF_Flag,Not_first_time ;Set flag so we do a find next rather
- ; than a find first. (re-use DTA!)
- JMP Find_Another_SubDirectory ;Keep checking for DIRs
-
- PAGE
- SUBTTL General use subroutines
- ;***************************************************************************;
- ;** G e n e r a l U s e S u b r o u t i n e s - start here **;
- ;***************************************************************************;
- ;-----------------------------------------------------------------------------;
- ; Get COMSPEC-search the environment for COMSPEC= string (loc of COMMAND.COM) ;
- ;-----------------------------------------------------------------------------;
- Get_COMSPEC:
- MOV ES,WORD PTR [Environment] ;Segment address of Environment
- XOR DI,DI ;Start at beginning of segment
- MOV SI,OFFSET COMPSEC_str ;Point to "compspec="string
- CLD ;Forward direction
- XOR AX,AX ;Constant of zero for comparison
- Check_Next_ENV_string:
- CMP BYTE PTR ES:[DI],0 ;If points to zero, no compspec
- JZ Missing_COMSPEC ; FATAL error....
- MOV DX,DI ;Save string pointers
- MOV BP,SI
- MOV CX,8 ;COMSPEC= is 8 characters
- REPZ CMPSB ;Check if we are pointing at comspec=
- MOV DI,DX ;Restore the pointers
- MOV SI,BP
- JZ Found_COMSPEC ;We've got a match
- MOV CX,200h ;Search for a max of 512 bytes
- REPNZ SCASB ;Search for zero byte (AL=0)
- JNZ Missing_COMSPEC ; FATAL error....
- JMP SHORT Check_Next_ENV_string ;Keep looking for environment strin
- Missing_COMSPEC:
- MOV DX,OFFSET Missing_CS_MSG ;Message to say comspec= missing
- JMP Error_Exit
- Found_COMSPEC:
- ADD DI,8 ;Point to string after COMSPEC=
- MOV WORD PTR [Command_Adr],DI ;Save address: offset
- MOV WORD PTR [Command_Adr+2],ES ; and SEGMENT too
- RET
-
- ;---------------------------------------------------------------;
- ; Create EXEC Parm block- setup the parameter block for DOS EXEC;
- ;---------------------------------------------------------------;
- Create_EXEC_parm_BLOCK:
- MOV [Parm_Block],ES ;Environment segment
- MOV [Parm_Block+4],CS ;Segment of parameter
- MOV [Parm_Block+8],CS ;Segment of FCB #1
- MOV [Parm_Block+12],CS ;Segment of FCB #2
- MOV AX,CS ;Point ES back to data segment
- MOV ES,AX
- RET
-
- ;----------------------------------------------------------------------;
- ; Create Command tail - setup /C followed by user's program to execute ;
- ; This program is later executed by invokation of COMMAND.COM ;
- ;----------------------------------------------------------------------;
- Create_Command_Tail:
- ; check program to invoke (parameter at 80h) AKA: PSP parameter
- MOV AL,PSP_PARM ;Check # of characters in parameter
- OR AL,AL ;Check if no characters (AL=0)
- JNZ Parameter_detected ; If a parameter passed..
- MOV DX,OFFSET XALL_Help_MSG ;If no input,put out syntax msg
- JMP Error_Exit
-
- Parameter_detected:
- ; Insert a " /C" in front of the PSP parameter
- ADD AL,3 ;Increase length by 3 for " /C"
- MOV [XALL_Parm],AL ;Store new character count
- MOV BYTE PTR[XALL_Parm+1],' ' ;Store blank separator
- MOV WORD PTR[XALL_Parm+2],'C/';Store /C (after this is actual parm)
- RET
-
-
- ;----------------------------------------------------------------------;
- ; Display XALL message - Display name of current directory we are ;
- ; executing the user's command in. ;
- ;----------------------------------------------------------------------;
- Display_XALL_MSG: ;Display name of current directory
- MOV DX, offset In_Dir_MSG ;Begining of "Xing in:" message
- MOV CX,12 ;message has 12 chars
- MOV AH,40h ;DOS Write func
- MOV BX,1 ;Handle for std output device
- INT 21h ;Write Start message
- ; Get the current directory string
- MOV SI,OFFSET Current_Dir ;Location to store directory string
- XOR DX,DX ;Default drive
- MOV AH,47h ;DOS Get directory function
- INT 21h
- ; Scan the string in Current_Dir to determine its length:
- MOV DI,SI ;Dir string start
- MOV DX,SI ;Save a copy for use later
- XOR AX,AX ;Scan for zero termination of string
- MOV CX,64 ;Scan up to 64 characters
- REPNE SCASB ;Find 1st zero byte
- SUB DI,DX ;Length of directory string
- MOV CX,DI ;Characters to display in dir string
- ;DX = start of dir strng, CX = # of chars in string
- MOV AH,40h ;DOS Write func
- INT 21h ;Display the actual directory string
- MOV DX,OFFSET CRLF_str ;Prepare to put out carriage ret + LF
- MOV CX,2 ;Print 2 characters
- MOV AH,40h ;DOS Write func
- INT 21h
- RET
-
- ;---------------------------------------------------------------;
- ; Error Exit - called with DX pointing to error message to send ;
- ;---------------------------------------------------------------;
- Error_Exit:
- MOV AH,09h ;DOS display string function
- INT 21h
-
- MOV DX,OFFSET Hit_Key_Msg ;Ask user to hit any key
- MOV AH,09h ;DOS display string function
- INT 21H
-
- ; Wait for user to hit any key
- XOR AX,AX
- INT 16h ;Wait for user to hit a key
-
- MOV AX,4C20h ;Terminate with 32 errorlevel
- INT 21h ;Terminate
-
-
- Normal_Termination:
- ; ;Terminate with zero (DOS) errorLEVEL
- MOV AX,4C00h
- INT 21h
-
- SUBTTL Definition of Data Structures
- PAGE
- ;-----------------------------------------------------------------;
- ; Data storage definition: ;
- ;-----------------------------------------------------------------;
- Current_Dir LABEL BYTE ;Overlay copyright msg with this
- XALL_CR_msg DB 'XALL 1.0 - high speed eXecute ALL subdirectories utility.'
- DB CR,LF
- DB CR,LF,"MIRDIR 1.0 ",BOX," PCDATA TOOLKIT (c) 1990"
- DB " Ziff Communications Co.",CR,LF
- DB "PC Magazine ",BOX," Wolfgang Stiller",CR,LF,"$"
- XALL_Help_MSG DB CR,LF,'Syntax is: "XALL anyDOScommand"',CR,LF
- DB ' "anyDOScommand" will then be eXecuted in the current and '
- DB 'all ',CR,LF
- DB ' subordinate subdirectories. The program or batch file to'
- DB ' be executed',CR,Lf
- DB ' must be included in the DOS PATH.$'
- Missing_CS_Msg LABEL BYTE ;A message starting with comspec strg
- COMPSEC_str DB 'COMSPEC=' ;String in environment to search for
- DB ' missing.',CR,LF,'$'
- XALL_Fail_msg DB 'XALL failure.',CR,LF
- DB 'Probably due to bad COMSPEC - no COMMAND.COM.',CR,LF,'$'
- EXEC_02_Msg DB 'Unable to find program.','$'
- EXEC_05_Msg DB 'Program access denied.','$'
- EXEC_08_Msg DB 'Too little free mem.','$'
- Hit_Key_Msg DB CR,LF,LF,'Please hit a key.'
- CRLF_Str DB CR,LF,'$'
- In_Dir_MSG DB CR,LF,'Xing in: \'
- COMMAND_Adr DD 00 ;Full address COMMAND.COM strng in ENV
- Global_str DB '*.*',0 ;String for find all files
- DotDot_str DB '..',0 ;String to return to mother directory
-
- Parm_Block DW 00 ;Parameter block for DOS EXEC command
- DW XALL_PARM,0
- DW 5Ch,0
- DW 6Ch,0
-
- FF_flag DB 0 ;First Find flag (=0 means find 1st)
- DTA_ptr DW DTA_AREA ;Pointer to a 43 char DTA block
- DTA_area LABEL BYTE ;area of 32 43 byte DTAs
- STACK_Bottom EQU DTA_area+ 32*43 ;Lower limit of the stack
- STACK_TOP EQU STACK_Bottom + 80h ;Allocate 128 byte stack
- Program_top EQU Stack_top+15 ;End of prog + 15 for paragr rounding
-
- CSEG EndS
- END XALL